package environment {
	import org.flixel.plugin.photonstorm.FlxVelocity;
	import org.flixel.FlxObject;
	import events.GameEvent;
	import events.GameEventManager;
	import states.GamePlayState;
	import character.Human;
	import org.flixel.FlxG;
	import org.flixel.FlxTilemap;
	import org.flixel.FlxPoint;
	import org.flixel.FlxGroup;
	import org.flixel.FlxSprite;
	/**
	 * @author NilsIH
	 */
	public class Hospital extends FlxGroup{
		
		[Embed(source="../img/hospital.png")] private var HospitalGFX : Class;
		
		public var _entranceTop:FlxSprite;
		public var _entranceLeft:FlxSprite;
		public var _entranceBottom:FlxSprite;
		public var _entranceRight:FlxSprite;
		
		private var _hospitalIdealTilemapData:Array;
		private var _hospitalDestroyTilemapData:Array;
		private var _hospitalTilemapData:Array;
		private var _hospitalTilemapData2:Array;
		
		public function get hospitalTilemapData():Array{
			return _hospitalTilemapData;
		}
		
		public function get hospitalTilemapData2():Array{
			return _hospitalTilemapData2;
		}
		
		private var _hospitalTilemap:FlxTilemap;
		private var _hospitalTilemapLayerAbove:FlxTilemap;
		
		private var _treatmentQueue:Array = [];
		private var _treatmentTime:Number = 3;
		private var _treatmentRemaining:Number = _treatmentTime;
		
		private var _maxActiveWorkers:int = 5;
		private var _currentActiveWorkers:int = 0;
		
		public var regenerationTime:Number = 33;
		private var _gameEventManager:GameEventManager;
		private var _reviveEvent:GameEvent;
		
		private var _destroyedParts:Array = new Array();
		private var _obliteratedParts:Array = new Array();
		private var _disabledParts:Array = new Array();
		
		private var _totalParts:uint = 22;
		
		private var _health:Number = 20;
		private var _maxHealth:Number = 20;
		
		public function Hospital(maxSize:uint = 0){
			super(maxSize);
			_entranceTop = new FlxSprite(FlxG.width / 2, (FlxG.height / 2) - 125);
			_entranceTop.makeGraphic(100, 1);
			_entranceLeft = new FlxSprite((FlxG.width / 2) - 150, FlxG.height / 2);
			_entranceLeft.makeGraphic(1, 100);
			_entranceBottom = new FlxSprite(FlxG.width / 2, (FlxG.height / 2) + 125);
			_entranceBottom.makeGraphic(100, 1);
			_entranceRight = new FlxSprite((FlxG.width / 2) + 150, FlxG.height / 2);
			_entranceRight.makeGraphic(1, 100);
			
			_gameEventManager = new GameEventManager();
			add(_gameEventManager);
			_reviveEvent = new GameEvent(revivePart, regenerationTime, hasReviveables, -1);
			_gameEventManager.add(_reviveEvent);
			
			_hospitalIdealTilemapData = [
			0, 	0, 	21, 25, 0, 	0,
			21, 25, 21, 21, 25, 21,
			25, 25, 21, 25, 21, 25,
			33, 23, 25, 25, 23,	24,
			0,	0,	23, 23, 0, 	0
			];
			
			_hospitalDestroyTilemapData = [
			0,	0,	14,	30,	0,	0,
			14, 34, 1, 	1, 	34, 30,
			8, 1, 	1, 	1, 	1, 	35,
			19, 20, 1, 1, 20,	32,
			0,	0,	19, 32, 0, 	0
			];
			
			_hospitalTilemapData = [
			0, 	0, 	0, 0, 0, 	0,
			0, 	0, 	21, 25, 0, 	0,
			21, 25, 21, 21, 25, 21,
			33, 23, 25, 25, 23,	24,
			0,	0,	23, 23, 0, 	0
			];
			_hospitalTilemap = new FlxTilemap();
			_hospitalTilemap.loadMap(FlxTilemap.arrayToCSV(_hospitalTilemapData, 6), HospitalGFX);
			_hospitalTilemap.x = 5 * 50;
			_hospitalTilemap.y = 3 * 50;
			add(_hospitalTilemap);
			
			_hospitalTilemapData2 = [
			0, 	0, 	21, 25, 0, 	0,
			21, 25, 0, 0, 25, 21
			];
			_hospitalTilemapLayerAbove = new FlxTilemap();
			_hospitalTilemapLayerAbove.loadMap(FlxTilemap.arrayToCSV(_hospitalTilemapData2, 6), HospitalGFX);
			_hospitalTilemapLayerAbove.x = 5 * 50;
			_hospitalTilemapLayerAbove.y = 3 * 50;
			
			//debug
			/*
			add(_entranceTop);
			add(_entranceBottom);
			add(_entranceLeft);
			add(_entranceRight);
			*/
		}
		
		public function closestEntrance(object:FlxSprite):FlxPoint {
			var distanceBottom:int = FlxVelocity.distanceBetween(object, _entranceBottom);
			var distanceTop:int = FlxVelocity.distanceBetween(object, _entranceTop);
			var distanceLeft:int = FlxVelocity.distanceBetween(object, _entranceLeft);
			var distanceRight:int = FlxVelocity.distanceBetween(object, _entranceRight);
			var shortestDistance:int = distanceBottom;
			var finalSpr:FlxSprite = _entranceBottom;
			if (distanceTop < shortestDistance){
				shortestDistance = distanceTop;
				finalSpr = _entranceTop;
			}
			if (distanceLeft < shortestDistance){
				shortestDistance = distanceLeft;
				finalSpr = _entranceLeft;
			}
			if (distanceRight < shortestDistance){
				shortestDistance = distanceRight;
				finalSpr = _entranceRight;
			}
			return new FlxPoint(finalSpr.x, finalSpr.y);
		}
		
		public function getRightTilemapFor(index:Number):Array{
			if (index == 2 || index == 3 || index == 6 || index == 7 || index == 10 || index == 11) return _hospitalTilemapData2;
			return _hospitalTilemapData;
		}
		
		public function get hospitalTilemapLayerAbove():FlxTilemap{
			return _hospitalTilemapLayerAbove;
		}
		
		public function revivePart():void{
			var index:Number = NiloUtils.getRandomElement(_destroyedParts) as Number;
			getRightTilemapFor(index)[index] = _hospitalIdealTilemapData[index];	
			_hospitalTilemap.loadMap(FlxTilemap.arrayToCSV(_hospitalTilemapData, 6), HospitalGFX);
			_hospitalTilemapLayerAbove.loadMap(FlxTilemap.arrayToCSV(_hospitalTilemapData2, 6), HospitalGFX);
		}
		
		public function hasReviveables():Boolean {
			if (_destroyedParts.length > 0){
				return true;
			}
			_reviveEvent.timedelay = regenerationTime;
			return false;
		}
		
		public function refreshHospitalParts():void {
			var i:uint = 0;
			for (i = 0; i < _obliteratedParts.length; i++){
				getRightTilemapFor(_obliteratedParts[i])[_obliteratedParts[i]] = 0;
			}
			for (i = 0; i < _destroyedParts.length; i++){
				getRightTilemapFor(_destroyedParts[i])[_destroyedParts[i]] = _hospitalDestroyTilemapData[_destroyedParts[i]];
			}
			_hospitalTilemap.loadMap(FlxTilemap.arrayToCSV(_hospitalTilemapData, 6), HospitalGFX);
			_hospitalTilemapLayerAbove.loadMap(FlxTilemap.arrayToCSV(_hospitalTilemapData2, 6), HospitalGFX);
		}
		
		public function horribleDeedDone(action:String, X:Number, Y:Number):void {
			var index:Number = X + (Y * 6);
			if (action == "fire"){
				_disabledParts.splice(_disabledParts.indexOf(index), 1);
				_destroyedParts.push(index);
			}
			else if (action == "explode"){
				_obliteratedParts.splice(_obliteratedParts.indexOf(index), 1);
				_destroyedParts.push(index);
			}
			refreshHospitalParts();
		}
		
		public function doAction(action:String, X:Number, Y:Number):Boolean {
			var index:Number = X + (Y * 6);
			if (action == "fire"){
				if (_disabledParts.indexOf(index) == -1 ) {
					_disabledParts.push(index);
					if (_destroyedParts.indexOf(index) != -1) {
						_destroyedParts.splice(_destroyedParts.indexOf(index), 1);
					}
				}
			}
			else if (action == "infest"){
				if (_disabledParts.indexOf(index) == -1 ) {
					_disabledParts.push(index);
					if (_destroyedParts.indexOf(index) != -1) {
						_destroyedParts.splice(_destroyedParts.indexOf(index), 1);
					}
				}
			}
			else if (action == "explode"){
				if (_destroyedParts.indexOf(index) != -1){
					if (_obliteratedParts.indexOf(index) == -1){
						_obliteratedParts.push(index);
					}
					_destroyedParts.splice(_destroyedParts.indexOf(index), 1);
					refreshHospitalParts();
					return true;
				}
				else {
					_destroyedParts.push(index);
				}
			}
			refreshHospitalParts();
			return false;
		}
		
		
		
		public function beginTreatingHuman(human:Human):void{
			if (human.type == "Regular") _treatmentQueue.push(human);
			else if (human.type == "Hospital") human.kill();
		}
		
		override public function update():void {
			super.update();
			if (_treatmentQueue.length > 0) {
				_treatmentRemaining -= FlxG.elapsed;
				if (_treatmentRemaining <= 0) {
					_treatmentRemaining = _treatmentTime;
					
					var spawnX:Number = _entranceBottom.x;
					var spawnY:Number = _entranceBottom.y;
					var veloX:Number = 0;
					var veloY:Number = 0;
					var human:Human = _treatmentQueue.pop() as Human;
					
					human.reset(spawnX, spawnY);
					human.velocity.x = veloX;
					human.velocity.y = veloY;
					human.changeDirection();
					human.initializeAs("Regular");
				}
			}
		}
		
		public function get canSpawnMore():Boolean {
			return _currentActiveWorkers < _maxActiveWorkers;
		}
		
		public function addWorkerToField():void{
			_currentActiveWorkers++;
		}
		
		public function removeWorkerFromField():void{
			_currentActiveWorkers--;	
		}
		
		public function damage(amt:Number):void {
			_health -= amt;
			if (_health <= 0){
				_health = _maxHealth;
				// Infect a random tile:
				var tile:int = (NiloTile.hospitalTiles.length * FlxG.random()) % NiloTile.hospitalTiles.length;
				var i:int = 0;
				while(((NiloTile.hospitalTiles[tile] as NiloTile).tileEffect != null) && i < NiloTile.hospitalTiles.length){
					tile = (tile + 1) % NiloTile.hospitalTiles.length;
					i++;
				}
				if (i < NiloTile.hospitalTiles.length){
					FlxG.log("INFEST");
					var niloTile:NiloTile = NiloTile.hospitalTiles[tile];
					niloTile.infuseTileWith("infest");
				}
			}
		}
		
		public function isCompletelyDestroyed():Boolean{
			return (_destroyedParts.length + _obliteratedParts.length >= _totalParts) || (_disabledParts.length >= _totalParts);
		}
		
	}
}
